package com.blue.gateway.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;


public final class DateUtil {
	

	private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
	
	private DateUtil() {
		
	}
	
	/**
	 * 一天的毫秒数
	 */
	public static final long DAY_MS = 24 * 60 * 60 * 1000L;

	/**
	 * 日期格式，年-月-日
	 */
	public static final String PATTERN_DAY = "yyyy-MM-dd";
	
	/**
	 * 日期格式，月-日
	 */
	public static final String PATTERN_MONRH_DAY = "MM-dd";
	
	/**
	 * 日期格式，年月日
	 */
	public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
	
	/**
	 * 日期格式，年月
	 */
	public static final String PATTERN_YYYYMM = "yyyyMM";

	/**
	 * 日期格式，年月日时分秒
	 */
	public static final String PATTERN_FULL = "yyyy-MM-dd HH:mm:ss";
	
	/**
	 * 日期格式，年月日时分秒
	 */
	public static final String PATTERN_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

	/**
	 * 日期格式，年月日T时分秒
	 */
	public static final String PATTERN_YYYYMMDDTHHMMSS = "yyyy-MM-dd'T'HH:mm:ss";

	/**
	 * 日期类型，年月
	 */
	public static final String PATTERN_YYYY_MM = "yyyy-MM";

	/**
	 * 分钟最小值
	 */
	public static final String MINUTE_MIN = " 00:00:00";

	/**
	 * 分钟最大值
	 */
	public static final String MINUTE_MAX = " 23:59:59";
	
	/**
	 * 默认的Date常量 当前时间
	 */
	private static final Date DEFAULT_DATE_VALUE = new Date();
	
	
	public static final DateUtil dateUtil = new DateUtil();
	
	public static DateUtil getInstance(){
		return dateUtil;
	}

	private static Map<String, ThreadLocal<SimpleDateFormat>> threadLocalMap = new ConcurrentHashMap<>();

	public static SimpleDateFormat getSimpleDateFormat(String pattern) {
		ThreadLocal<SimpleDateFormat> threadLocal = threadLocalMap.get(pattern);
		if (threadLocal == null) {
			threadLocal = new ThreadLocal<>();
			threadLocalMap.put(pattern, threadLocal);
		}
		SimpleDateFormat sdf = threadLocal.get();
		if (sdf == null) {
			sdf = new SimpleDateFormat(pattern);
			threadLocal.set(sdf);
		}
		return sdf;
	}
	
	
	public static String formatDateMan(Date date, String pattern) {
		if (date != null) {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			return sdf.format(date);
		} else {
			return "";
		}
	}

	/**
	 * 格式化日期（yyyy-MM-dd）
	 * 
	 * @param date
	 *            日期
	 * @return 格式化日期字符串
	 */
	public static String formatDate(Date date) {
		SimpleDateFormat sdf = getSimpleDateFormat(PATTERN_DAY);
		if (date != null) {
			return sdf.format(date);
		} else {
			return sdf.format(DEFAULT_DATE_VALUE);
		}
	}
	
	/**
	 * 格式化日期（yyyy-MM-dd hh:mm:ss）
	 * 
	 * @param date  日期
	 * @return 格式化日期字符串
	 */
	public static String formatDateYMDHMS(Date date) {
		SimpleDateFormat sdf = getSimpleDateFormat(PATTERN_FULL);
		if (date != null) {
			return sdf.format(date);
		} else {
			return sdf.format(DEFAULT_DATE_VALUE);
		}
	}

	/**
	 * 格式化日期（指定格式）
	 * 
	 * @param date
	 *            日期
	 * @return 格式化日期字符串
	 */
	public static String formatDate(Date date, String pattern) {
		if (date != null) {
			SimpleDateFormat sdf = getSimpleDateFormat(pattern);
			return sdf.format(date);
		} else {
			return "";
		}
	}

	/**
	 * 格式化时间（yyyy-MM-dd HH:mm:ss）
	 * 
	 * @param date
	 *            时间
	 * @return 格式化时间字符串
	 */
	public static String formatTime(Date date) {
		if (date != null) {
			return formatDate(date, PATTERN_FULL);
		} else {
			return "";
		}
	}

	/**
	 * 将以字符串形式表示的日期转换为Date类型
	 * 
	 * @param dateStr
	 *            日期字符串
	 * @param pattern
	 *            格式
	 * @return 日期对象
	 * @throws Exception
	 */
	public static Date parseDate(String dateStr, String pattern) {
		try {
			SimpleDateFormat sdf = getSimpleDateFormat(pattern);
			return sdf.parse(dateStr);
		} catch (Exception e) {
			logger.error("parseDate has cause exception", e);
			return DEFAULT_DATE_VALUE;
		}
	}

	/**
	 * 计算2个日期的差值（根据不同的时间单位计算出不同时间单位的差值）
	 * 
	 * @param start
	 * @param end
	 * @param unit
	 *            时间单位
	 * @return 时间差值（单位与unit参数单位相同.当end>start返回正值，否则返回负值）
	 */
	public static long between(Date start, Date end, TimeUnit unit) {

		if (start == null || end == null || unit == null) {
			return 0;
		}

		long duration = end.getTime() - start.getTime();
		return unit.convert(duration, TimeUnit.MILLISECONDS);
	}

	/**
	 * 计算时间是否是在指定的时间范围内
	 * 
	 * @author lierlin
	 * @param date
	 * @param start
	 * @param end
	 * @return
	 */
	public static boolean isBetween(Date date, Date start, Date end) {
		return (date.getTime() > start.getTime()) && (date.getTime() < end.getTime());
	}

	/**
	 * 获取一天中的最早时间 00:00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getFirstOfADay(String date) throws Exception {
		return getFirstOfADay(parseDate(date, DateUtil.PATTERN_DAY));
	}

	/**
	 * 获取一天中的最晚时间 23:59:59
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfADay(String date) throws Exception {
		return getEndOfADay(parseDate(date, DateUtil.PATTERN_DAY));
	}

	/**
	 * 获取一天中的最早时间 00:00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getFirstOfADay(Date date) throws Exception {
		SimpleDateFormat sdf = getSimpleDateFormat(PATTERN_DAY);
		return getSimpleDateFormat(PATTERN_FULL).parse(
				sdf.format(date) + MINUTE_MIN);
	}

	/**
	 * 获取一天中的最晚时间 23:59:59
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfADay(Date date) throws Exception {
		SimpleDateFormat sdf = getSimpleDateFormat(PATTERN_DAY);
		return getSimpleDateFormat(PATTERN_FULL).parse(
				sdf.format(date) + MINUTE_MAX);
	}

	/**
	 * 获取一周中的最早时间 00:00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getFirstOfAWeek(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		return getFirstOfADay(calendar.getTime());
	}

	/**
	 * 获取一周中的最晚时间 23:59:59
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfAWeek(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
		calendar.add(Calendar.DATE, 7); // 依照中国的习惯，获取到周末以后必须往后推一个星期
		return getEndOfADay(calendar.getTime());
	}

	/**
	 * 获取一个月中的最早时间 00:00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getFirstOfAMonth(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DATE, 1);
		return getFirstOfADay(calendar.getTime());
	}

	/**
	 * 获取一个月中的最晚时间 23:59:59
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfAMonth(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DATE, 1);
		calendar.roll(Calendar.DATE, -1);
		return getEndOfADay(calendar.getTime());
	}

	/**
	 * 获取上个月的最早时间 00:00:00
	 * 
	 * @param date
	 * @return
	 */
	public static Date getFirstOfLastMonth(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -1);
		return getFirstOfAMonth(calendar.getTime());
	}

	/**
	 * 获取上个月中的最晚时间 23:59:59
	 * 
	 * @param date
	 * @return
	 */
	public static Date getEndOfLastMonth(Date date) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -1);
		return getEndOfAMonth(calendar.getTime());
	}

	/**
	 * 获取两个时间的差的天数
	 */
	public static int dateSub(Date date1, Date date2) {
		return (int) Math.ceil((date1.getTime() - date2.getTime())
				/ (24 * 60 * 60 * 1000.0));
	}

	/**
	 * 根据天数差值获取新的日期
	 * 
	 * @param date
	 * @param days
	 * @return
	 */
	public static Date getDateByAddDays(Date date, int days) {
		Calendar calender = Calendar.getInstance();
		calender.setTime(date);
		calender.add(Calendar.DAY_OF_MONTH, days);
		return calender.getTime();
	}

	/**
	 * 根据当前日期和天数差值获取新的日期
	 * 
	 * @param days
	 * @return
	 */
	public static Date getDateByAddDays(int days) {
		Date date = new Date();
		return getDateByAddDays(date, days);
	}

	/**
	 * 根据天数差值获取新的日期格式化字符串
	 * 
	 * @param date
	 * @param days
	 * @return
	 */
	public static String getDateStrByAddDays(Date date, int days) {
		Date newDate = getDateByAddDays(date, days);
		return formatDate(newDate);
	}

	/**
	 * 根据当前日期和天数差值获取新的日期格式化字符串
	 * 
	 * @param days
	 * @return
	 */
	public static String getDateStrByAddDays(int days) {
		Date newDate = getDateByAddDays(days);
		return formatDate(newDate);
	}

	/**
	 * 根据当前日期和天数差值获取新的月份
	 * @param date
	 * @param months
	 * @return
	 */
	public static Date getMonthByAddMonths(Date date, int months) {
		Calendar calender = Calendar.getInstance();
		calender.setTime(date);
		calender.add(Calendar.MONTH, months);
		return calender.getTime();
	}

	/**
	 * 根据当前日期和天数差值获取新的月份
	 * @param months
	 * @return
	 */
	public static Date getMonthByAddMonths(int months) {
		Date date = new Date();
		return getMonthByAddMonths(date, months);
	}

	/**
	 * 根据当前日期和天数差值获取新的月份字符串
	 * @param months
	 * @return
	 */
	public static String getMonthStrByAddMonths(int months) {
		return formatDate(getMonthByAddMonths(months), PATTERN_YYYY_MM);
	}

}
